/*
  Part of the MasterTool3D project - http://code.google.com/p/master-tool-3d

  Copyright (c) 2011 Ingo Pueschl

  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation, version 2.1.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General
  Public License along with this library; if not, write to the
  Free Software Foundation, Inc., 59 Temple Place, Suite 330,
  Boston, MA  02111-1307  USA
*/

package techjit.gfx.core;

import java.util.ArrayList;

import processing.core.PApplet;
import techjit.gfx.util.PU;
import techjit.gfx.util.geo.Dimensions;
import techjit.gfx.util.geo.ScreenVector;
import techjit.gfx.util.geo.Vector;
import techjit.util.LogManager;
import techjit.util.RuntimeParams;

public class GFX_Scene extends GFX_Object {

	// FIELDS
	// head
	private int sceneId;
	private static int nextSceneId = RuntimeParams.GFX__FIRST_ID;

	private GFX_LineLayout topLineLayout;

	public ArrayList<GFX_Edge> edges = new ArrayList<GFX_Edge>();

	public GFX_SceneElement currentSceneElement = null;
	public ScreenVector currentSceneElement_screenPosition = null;

	private Vector relPos = new Vector(0);

	// CONSTRUCTORS
	public GFX_Scene() {
		// header
		super();
		sceneId = nextSceneId++;

		// body
		// this.parentVisualizer = parentVisualizer;

		// tail
		logConstructorResult();
	}

	// METHODS
	public void addEdge(GFX_Edge edge) {
		edges.add(edge);
	}

	public void addTopLineLayout(GFX_LineLayout topLineLayout) {
		// body
		this.topLineLayout = topLineLayout;
		topLineLayout.changeParent(this);
		// tail
		logAddElementsResult();
	}

	public void arrange() {
		// head
		if (RuntimeParams.GFX_OBJECT__LOG_ARRANGEMENT_RESULT) {
			logArrangementInvocation();
		}

		// arrange
		if (topLineLayout == null) {
			// relDims = new Dimensions(1, 2, 3);
		} else {
			topLineLayout.arrange();
			float width = topLineLayout.relDims.getWidth();
			float height = topLineLayout.relDims.getHeight();
			float depth = topLineLayout.relDims.getDepth();
			relDims = new Dimensions(width, height, depth);
		}

		// tail
		logLocalArrangementResult();
	}

	public void change_currentSceneElement_screenPosition(
			ScreenVector currentSceneElement_screenPosition) {
		this.currentSceneElement_screenPosition = currentSceneElement_screenPosition;
	}

	public void changeCurrentSceneElement(GFX_SceneElement currentSceneElement) {
		this.currentSceneElement = currentSceneElement;
	}

	public void changeCurrentSceneElement_chooseByMousePosition() {

	}

	// @Override
	public void changeRelativePosition(Vector relPos) {
		// super.changeRelativePosition(relPos);
		this.relPos = relPos;
	}

	public void changeRelativePosition_centerAtWorldOrigin() {
		Vector halfDimensions = getRelativeDimensions(new Vector(.5f));
		// LogManager.debugIP("halfDimensions = " + halfDimensions);
		changeRelativePosition(halfDimensions.getInverse());
	}

	public boolean currentSceneElementHasChildren() {
		GFX_SceneElement current = currentSceneElement;
		if (current.isLayout() && ((GFX_Layout) current).hasChildElements()) {
			return true;
		} else {
			return false;
		}

	}

	public boolean currentSceneElementIsFirst() {
		GFX_SceneElement current = currentSceneElement;
		if (current.isTopLayout()) {
			return true;
		} else {
			GFX_Layout parentLayout = (GFX_Layout) current
					.navi_getParentObject();
			if (current == parentLayout.navi_getFirstChild()) {
				return true;
			} else {
				return false;
			}
		}
	}

	public boolean currentSceneElementIsLast() {
		GFX_SceneElement current = currentSceneElement;
		if (current.isTopLayout()) {
			return true;
		} else {
			GFX_Layout parentLayout = (GFX_Layout) current
					.navi_getParentObject();
			if (current == parentLayout.navi_getLastChild()) {
				return true;
			} else {
				return false;
			}
		}
	}

	public boolean currentSceneElementIsTopLayout() {
		GFX_SceneElement current = currentSceneElement;
		if (current.navi_getParentObject() == this) {
			return true;
		} else {
			return false;
		}
	}

	@Override
	public void draw(PApplet p) {
		// head
		p.pushMatrix();
		{
			PU.translate(p, new Vector(relPos));
			// <>
			// modelOriginPointer = relPos.getInverse();

			// </>
			super.draw(p);

			// <>
			// modelOriginPointer.draw(p);
			// </>

			// body
			if (topLineLayout != null) {
				topLineLayout.draw(p);
			}

			// <>
			// for (GFX_Edge edge : edges) {
			// edge.draw(p);
			// }
			// </>

		}
		// tail
		p.popMatrix();
	}

	public int get_currentSceneElement_screenPositionX() {
		return currentSceneElement_screenPosition.getX();
	}

	public int get_currentSceneElement_screenPositionY() {
		return currentSceneElement_screenPosition.getY();
	}

	public GFX_SceneElement getCurrentSceneElement() {
		return currentSceneElement;
	}

	public GFX_LineLayout getTopLineLayout() {
		return topLineLayout;
	}

	// public SoftwareVisualizer getParentVisualizer() {
	// return parentVisualizer;
	// }

	// private Vector getRelativePosition(Vector factor) {
	// return new Vector(relPos.getX() * factor.getX(), relPos.getY()
	// * factor.getY(), relPos.getZ() * factor.getZ());
	// }

	protected boolean isCurrentSceneElement(GFX_SceneElement currentSceneElement) {
		if (currentSceneElement == this.currentSceneElement) {
			return true;
		} else {
			return false;
		}
	}

	@Override
	public void log() {
		LogManager.logALL("" + this);
		LogManager.indent();
		{
			// LogManager.logALL("parentVisualizer = " + parentVisualizer);
			LogManager.logALL("layout = " + topLineLayout);
			super.log();
		}
		LogManager.deindent();
	}

	public boolean navi_chooseFirstChild() {
		if (RuntimeParams.NAVI__ONLY_ON_NODES) {
			if (currentSceneElement instanceof GFX_Node) {
				GFX_Node currentNode = (GFX_Node) currentSceneElement;
				GFX_LineLayout parentLineLayout = (GFX_LineLayout) currentNode
						.navi_getParentObject();
				GFX_SceneElement lastChild = parentLineLayout
						.navi_getLastChild();
				if (lastChild instanceof GFX_CircleLayout) {
					GFX_CircleLayout circleLayout = (GFX_CircleLayout) lastChild;
					GFX_LineLayout lineLayout = (GFX_LineLayout) circleLayout
							.navi_getFirstChild();
					currentSceneElement = lineLayout.navi_getFirstChild();
					return true;
				}
				return false;
			}
			return false;
		} else {
			if (currentSceneElement instanceof GFX_Layout) {
				GFX_Layout currentLayout = (GFX_Layout) currentSceneElement;
				if (currentLayout.hasChildElements()) {
					GFX_SceneElement child = currentLayout.navi_getFirstChild();
					if (child == currentSceneElement) {
						return false;
					}
					currentSceneElement = child;
					return true;
				}
				return false;
			}
			return false;
		}
	}

	public boolean navi_chooseFirstSibling() {
		if (RuntimeParams.NAVI__ONLY_ON_NODES) {
			if (currentSceneElement instanceof GFX_Node) {
				GFX_Node currentNode = (GFX_Node) currentSceneElement;
				GFX_LineLayout parentLineLayout = (GFX_LineLayout) currentNode
						.navi_getParentObject();
				if (parentLineLayout.isTopLayout()) {
					return false;
				}
				GFX_CircleLayout parentCircleLayout = (GFX_CircleLayout) parentLineLayout
						.navi_getParentObject();
				GFX_Node firstSiblingNode = parentCircleLayout
						.navi_getFirstChildNode();
				if (firstSiblingNode == currentSceneElement) {
					return false;
				}
				currentSceneElement = firstSiblingNode;
				return true;
			}
			return false;
		} else {
			if (currentSceneElement.isTopLayout()) {
				return false;
			}
			GFX_Layout parentLayout = (GFX_Layout) currentSceneElement
					.navi_getParentObject();
			GFX_SceneElement firstSibling = parentLayout.navi_getFirstChild();
			if (firstSibling == currentSceneElement) {
				return false;
			}
			currentSceneElement = firstSibling;
			return true;
		}
	}

	public boolean navi_chooseLastSibling() {
		if (RuntimeParams.NAVI__ONLY_ON_NODES) {
			if (currentSceneElement instanceof GFX_Node) {
				GFX_Node currentNode = (GFX_Node) currentSceneElement;
				GFX_LineLayout parentLineLayout = (GFX_LineLayout) currentNode
						.navi_getParentObject();
				if (parentLineLayout.isTopLayout()) {
					return false;
				}
				GFX_CircleLayout parentCircleLayout = (GFX_CircleLayout) parentLineLayout
						.navi_getParentObject();
				GFX_Node lastSiblingNode = parentCircleLayout
						.navi_getLastChildNode();
				if (lastSiblingNode == currentSceneElement) {
					return false;
				}
				currentSceneElement = lastSiblingNode;
				return true;
			}
			return false;
		} else {
			if (currentSceneElement.isTopLayout()) {
				return false;
			}
			GFX_Layout parentLayout = (GFX_Layout) currentSceneElement
					.navi_getParentObject();
			GFX_SceneElement lastSibling = parentLayout.navi_getLastChild();
			if (lastSibling == currentSceneElement) {
				return false;
			}
			currentSceneElement = lastSibling;
			return true;
		}
	}

	public boolean navi_chooseNextSibling() {
		if (RuntimeParams.NAVI__ONLY_ON_NODES) {
			if (currentSceneElement instanceof GFX_Node) {
				GFX_Node currentNode = (GFX_Node) currentSceneElement;
				GFX_LineLayout parentLineLayout = (GFX_LineLayout) currentNode
						.navi_getParentObject();
				if (parentLineLayout.isTopLayout()) {
					return false;
				}
				GFX_CircleLayout parentCircleLayout = (GFX_CircleLayout) parentLineLayout
						.navi_getParentObject();
				GFX_Node nextSiblingNode = parentCircleLayout
						.navi_getNextChildNode(parentLineLayout);
				if (nextSiblingNode == currentSceneElement) {
					return false;
				}
				currentSceneElement = nextSiblingNode;
				return true;
			}
			return false;
		} else {
			if (currentSceneElement.isTopLayout()) {
				return false;
			}
			GFX_Layout parentLayout = (GFX_Layout) currentSceneElement
					.navi_getParentObject();
			GFX_SceneElement nextSibling = parentLayout
					.navi_getNextChild(currentSceneElement);
			if (nextSibling == currentSceneElement) {
				return false;
			}
			currentSceneElement = nextSibling;
			return true;
		}
	}

	public boolean navi_chooseParent() {
		if (RuntimeParams.NAVI__ONLY_ON_NODES) {
			if (currentSceneElement instanceof GFX_Node) {
				GFX_Node currentNode = (GFX_Node) currentSceneElement;
				if (currentNode.isTopNode()) {
					return false;
				}
				GFX_LineLayout parentLineLayout1 = (GFX_LineLayout) currentNode
						.navi_getParentObject();
				GFX_CircleLayout parentCircleLayout = (GFX_CircleLayout) parentLineLayout1
						.navi_getParentObject();
				GFX_LineLayout parentLineLayout2 = (GFX_LineLayout) parentCircleLayout
						.navi_getParentObject();
				currentSceneElement = parentLineLayout2.navi_getFirstChild();
				return true;
			}
			return false;
		} else {
			if (currentSceneElementIsTopLayout()) {
				return false;
			}
			currentSceneElement = (GFX_SceneElement) currentSceneElement
					.navi_getParentObject();
			return true;
		}
	}

	public boolean navi_choosePreviousSibling() {
		if (RuntimeParams.NAVI__ONLY_ON_NODES) {
			if (currentSceneElement instanceof GFX_Node) {
				GFX_Node currentNode = (GFX_Node) currentSceneElement;
				GFX_LineLayout parentLineLayout = (GFX_LineLayout) currentNode
						.navi_getParentObject();
				if (parentLineLayout.isTopLayout()) {
					return false;
				}
				GFX_CircleLayout parentCircleLayout = (GFX_CircleLayout) parentLineLayout
						.navi_getParentObject();
				GFX_Node previousSiblingNode = parentCircleLayout
						.navi_getPreviousChildNode(parentLineLayout);
				if (previousSiblingNode == currentSceneElement) {
					return false;
				}
				currentSceneElement = previousSiblingNode;
				return true;
			}
			return false;
		} else {
			if (currentSceneElement.isTopLayout()) {
				return false;
			}
			GFX_Layout parentLayout = (GFX_Layout) currentSceneElement
					.navi_getParentObject();
			GFX_SceneElement previousSibling = parentLayout
					.navi_getPreviousChild(currentSceneElement);
			if (previousSibling == currentSceneElement) {
				return false;
			}
			currentSceneElement = previousSibling;
			return true;
		}
	}

	public boolean navi_chooseTop() {
		if (RuntimeParams.NAVI__ONLY_ON_NODES) {
			if (currentSceneElement instanceof GFX_Node) {
				GFX_Node currentNode = (GFX_Node) currentSceneElement;
				GFX_Node topNode = (GFX_Node) topLineLayout
						.navi_getFirstChild();
				if (topNode == currentNode) {
					return false;
				}
				currentSceneElement = topNode;
				return true;
			}
			return false;
		} else {
			if (currentSceneElement.isTopLayout()) {
				return false;
			}
			currentSceneElement = topLineLayout;
			return true;
		}
	}

	@Override
	public String toString() {
		return "<GFX_Scene " + sceneId + ">";
	}

}
